package unit22.sourceAnnotation;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;

import com.oracle.webservices.internal.api.message.PropertySet.Property;
@SupportedAnnotationTypes("sourceAnnotations.Property")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BeanInfoAnnotationProcessor extends AbstractProcessor{

	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		// TODO Auto-generated method stub
		for(TypeElement e:annotations){
			Map<String , Property> props= new LinkedHashMap<>();
			String beanClassName=null;
			for(javax.lang.model.element.Element ele:roundEnv.getElementsAnnotatedWith(e)){
				String mname=e.getSimpleName().toString();
				String[] prefixes={"get","set","is"};
				boolean found=false;
				for(int x=0;!found&&x<prefixes.length;x++)
					if(mname.startsWith(prefixes[x])){
						found=true;
						int start=prefixes[x].length();
						String name=Introspector.decapitalize(mname.substring(start));
						props.put(name, e.getAnnotation(Property.class));
					}
				if(!found)
					processingEnv.getMessager().printMessage(Kind.ERROR, "@Property must be applied to getXXX ,setXXX, or isXXX method", ele);
				else if(beanClassName==null)
					beanClassName=((TypeElement) ele.getEnclosingElement()).getQualifiedName().toString();
				}
			try {
				if(beanClassName!=null)
					writeBeanInfoFile(beanClassName,props);
			} catch (Exception e2) {
				// TODO: handle exception
				e2.printStackTrace();
				}
			}
		return true;
	}

	private void writeBeanInfoFile(String beanClassName, Map<String, Property> props) throws IOException {
		// TODO Auto-generated method stub
		JavaFileObject sourceFile=processingEnv.getFiler().createSourceFile(beanClassName+beanClassName);
		PrintWriter out=new PrintWriter(sourceFile.openWriter());
		int x=beanClassName.lastIndexOf(".");
		if(x>0){
			out.print("package ");
			out.print(beanClassName.substring(0,x));
			out.print(";");
		}
		out.print("public class ");
		out.print(beanClassName.substring(x+1));
		out.print("BeanInfo extends java.beans.SimpleBeanInfo");
		out.print("{");
		out.print("    public java.beans.propertyDescriptor[] getPropertyDescriptors()");
		out.print("{");
		out.print("        try{");
		for(Entry<String, Property> e:props.entrySet()){
		out.print("            java.beans.PropertyDescriptor ");
		out.print(e.getKey());
		out.print("Descriptor");
		out.print(" 					=new java.beans.PropertyDescriptor(\"");
		out.print(e.getKey());
		out.print("\", ");
		out.print(beanClassName);
		out.print(".class);");
//		String ed=e.getValue().editor().toString();
	}
	}
	

}
